/*
 * Copyright (C), 2017-2017, Night’s Watch
 * I pledge my life and honor to the Night’s Watch, 
 * for this night and all the nights to come.
 * FileName: RedisBase.java
 * Author:   DELL
 * Date:     2017年9月23日 下午12:02:04
 * Description: //模块目的、功能描述      
 * History: //修改记录
 * <author>      <time>      <version>    <desc>
 * 修改人姓名             修改时间            版本号                  描述
 */
package com.xzx.masterslave.masterslave.utils;


import com.google.common.collect.Maps;
import com.xzx.masterslave.masterslave.config.RedisProperties;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

/**
 * 〈Redis 工具类〉<br>
 *
 * @author hans
 */
@Component
public class CacheUtils {
	private static Logger logger = LoggerFactory.getLogger(CacheUtils.class);
	public static int A_DAY_SECONDS = 86400;
	public static int A_MONTH_SECONDS = 2592000;
	@SuppressWarnings("unused")
	private static RedisProperties redisProperties;
	private static JedisPool jedisPool = null;
	@Autowired
	public  void setRedisProperties(RedisProperties redisProperties) {
		CacheUtils.redisProperties = redisProperties;
		JedisPoolConfig config = new JedisPoolConfig();
		config.setMaxTotal(Integer.parseInt(redisProperties.getMaxTotal()));
		config.setMaxIdle(Integer.parseInt(redisProperties.getMaxIdle()));
		config.setMaxWaitMillis(Long.parseLong(redisProperties.getMaxWaitMillis()));
		config.setTestOnBorrow(true);
		if (StringUtils.isNotEmpty(redisProperties.getPassword())) {
			jedisPool = new JedisPool(config, redisProperties.getIp(), Integer.parseInt(redisProperties.getPort()), Integer.parseInt(redisProperties.getTimeOut()), redisProperties.getPassword());
		} else {
			jedisPool = new JedisPool(config, redisProperties.getIp(), Integer.parseInt(redisProperties.getPort()), Integer.parseInt(redisProperties.getTimeOut()));
		}
	}

	public static Long incr(String key) {
		return execute((Jedis jedis) -> jedis.incr(key));
	}

	public static Long incrby(String key, Integer integer) {
		return execute((Jedis jedis) -> jedis.incrBy(key, integer));
	}

	public static Long incr(String key, int seconds) {
		Long result = execute((Jedis jedis) -> jedis.incr(key));
		execute((Jedis jedis) -> jedis.expire(key, seconds));
		return result;
	}

	public static Integer checkIncrKey(String key) {
		String value = CacheUtils.get(key);
		try {
			return Integer.parseInt(value);
		} catch (Exception e) {
			return 0;
		}
	}

	public static Long expire(String key, int seconds) {
		return execute((Jedis jedis) -> jedis.expire(key, seconds));
	}

	public static void set(String key, String value) {
		execute((Jedis jedis) -> jedis.set(key, value));
	}

	public static void set(String key, String value, int seconds) {
		execute((Jedis jedis) -> jedis.set(key, value));
		execute((Jedis jedis) -> jedis.expire(key, seconds));
	}

	public static Set<String> keys(String pattern) {
		return execute((Jedis jedis) -> jedis.keys(pattern + "*"));
	}

	public static void set(String key, Object value) {
		execute((Jedis jedis) -> jedis.hmset(key, convertToMap(value)));
	}

	public static void set(String key, Object value, int seconds) {
		execute((Jedis jedis) -> jedis.hmset(key, convertToMap(value)));
		execute((Jedis jedis) -> jedis.expire(key, seconds));
	}

	public static <T> T get(String key, Class<T> klass) {
		Map<String, String> map = execute((Jedis jedis) -> jedis.hgetAll(key));
		return convertFromMap(map, klass);
	}

	public static void set(byte[] key, byte[] value) {
		execute((Jedis jedis) -> jedis.set(key, value));
	}

	public static void set(byte[] key, byte[] value, int seconds) {
		execute((Jedis jedis) -> jedis.set(key, value));
		execute((Jedis jedis) -> jedis.expire(key, seconds));
	}

	public static <T> T get(byte[] key, Class<T> klass) {
		byte[] result = execute((Jedis jedis) -> jedis.get(key));
		return SerializeUtils.deserialize(result, klass);
	}

	public static String get(String key) {
		return execute((Jedis jedis) -> jedis.get(key));
	}

	public static String hget(String key, String field) {
		if (field == null) {
			return null;
		}
		return execute((Jedis jedis) -> jedis.hget(key, field));
	}

	public static Map<String, String> hgetAll(String key) {
		return execute((Jedis jedis) -> jedis.hgetAll(key));
	}

	public static List<String> lrangerall(String key) {
		return execute((Jedis jedis) -> jedis.lrange(key, 0, -1));
	}

	public static void lpush(String key, String... inputs) {
		execute((Jedis jedis) -> jedis.lpush(key, inputs));
	}

	public static void rpush(String key, String... inputs) {
		execute((Jedis jedis) -> jedis.rpush(key, inputs));
	}

	public static void hset(String key, String field, String value) {
		if (field == null) {
			return;
		}
		execute((Jedis jedis) -> jedis.hset(key, field, value));
	}

	public static void hdel(String key, String field) {
		if (field == null) {
			return;
		}
		execute((Jedis jedis) -> jedis.hdel(key, field));
	}

	public static void hset(String key, Map<String, String> hash) {
		execute((Jedis jedis) -> jedis.hmset(key, hash));
	}

	public static void zincr(String key, String value) {
		execute((Jedis jedis) -> jedis.zincrby(key, 1, value));
	}

	public static Set<String> zrevrange(String key) {
		return execute((Jedis jedis) -> jedis.zrevrange(key, 0, 10));
	}

	public static void del(String key) {
		execute((Jedis jedis) -> jedis.del(key));
	}

	public static void del(byte[] key) {
		execute((Jedis jedis) -> jedis.del(key));
	}

	public static void zadd(String key, String member, Double score) {
		execute((Jedis jedis) -> jedis.zadd(key, score, member));
	}

	public static void zadd(String key, Map<String, Double> scoreMembers) {
		execute((Jedis jedis) -> jedis.zadd(key, scoreMembers));
	}

	@SuppressWarnings("unchecked")
	private static Map<String, String> convertToMap(Object arg) {
		try {
			if (arg instanceof Map) {
				return (Map<String, String>) arg;
			}
			Map<String, String> returnMap = BeanUtils.describe(arg);
			returnMap.remove("class");
			Map<String, String> result = Maps.newHashMapWithExpectedSize(returnMap.size());
			Set<Entry<String, String>> entrySet = returnMap.entrySet();
			for (Entry<String, String> entry : entrySet) {
				if (StringUtils.isNotEmpty(entry.getValue())) {
					result.put(entry.getKey(), entry.getValue());
				}
			}
			return result;
		} catch (IllegalAccessException e) {
			logger.warn(e.getMessage(), e);
		} catch (InvocationTargetException e) {
			logger.warn(e.getMessage(), e);
		} catch (NoSuchMethodException e) {
			logger.warn(e.getMessage(), e);
		}
		return new HashMap<String, String>();
	}

	private static <T> T convertFromMap(Map<String, String> map, Class<T> klass) {
		try {
			T t = klass.newInstance();
			BeanUtils.copyProperties(t, map);
			return t;
		} catch (IllegalAccessException e) {
			logger.warn(e.getMessage(), e);
		} catch (InvocationTargetException e) {
			logger.warn(e.getMessage(), e);
		} catch (InstantiationException e) {
			logger.warn(e.getMessage(), e);
		}
		return null;
	}

	private CacheUtils() {
	}

	static {
		/*  try {
		    Properties prop = new Properties();
		    prop.load(CacheUtils.class.getClassLoader().getResourceAsStream("cache.properties"));
		    String ip = prop.getProperty("ip");
		    String port = prop.getProperty("port", "6379");
		    String timeout = prop.getProperty("timeout", "3000");
		    String password = prop.getProperty("password");
		    String maxTotal = prop.getProperty("maxTotal", "100");
		    String maxIdle = prop.getProperty("maxIdle", "30");
		    String maxWaitMillis = prop.getProperty("maxWaitMillis", "1000");
		
		    JedisPoolConfig config = new JedisPoolConfig();
		    config.setMaxTotal(Integer.parseInt(maxTotal));
		    config.setMaxIdle(Integer.parseInt(maxIdle));
		    config.setMaxWaitMillis(Long.parseLong(maxWaitMillis));
		    config.setTestOnBorrow(true);
		
		    if (StringUtils.isNotEmpty(password)) {
		        jedisPool = new JedisPool(config, ip, Integer.parseInt(port), Integer.parseInt(timeout), password);
		    } else {
		        jedisPool = new JedisPool(config, ip, Integer.parseInt(port), Integer.parseInt(timeout));
		    }
		} catch (Exception e) {
		    logger.error(ExceptionUtils.getFullStackTrace(e));
		    throw new RuntimeException("CacheUtils init failer", e);
		}*/
	}
	private interface RedisBussiness<T> {
		T execute(Jedis jedis);
	}

	private static <T> T execute(RedisBussiness<T> exeIntf) {
		Jedis jedis = null;
		T result = null;
		try {
			jedis = jedisPool.getResource();
			result = exeIntf.execute(jedis);
		} catch (Exception e) {
			logger.error(ExceptionUtils.getFullStackTrace(e));
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
		return result;
	}
}
